/**
 * Copyright (c) 2020-2024, huli.com
 * All rights reserved.
 */
package com.xiaohujr.xuexue.leetcode.interview;

import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Xue Xue (xuexue1@huli.com)
 * @version 1.0
 * @since 2021/2/2
 */
public class ProducerConsumerSM {

    private AtomicInteger goodsCount;
    private static final Integer MAX_SIZE = 10;
    private Semaphore producerSm;
    private Semaphore consumerSm;
    private volatile boolean add = true;

    public ProducerConsumerSM(int goodsCount, int producerCount, int consumerCount) {
        this.goodsCount = new AtomicInteger(goodsCount);
        this.producerSm = new Semaphore(producerCount);
        this.consumerSm = new Semaphore(consumerCount);
    }

    private Runnable producerR = () -> {
        while (true) {
            while (add) {
                try {
                    producerSm.acquire();
                    if (goodsCount.get() < MAX_SIZE) {
                        Thread.sleep(200);
                        System.out.println(Thread.currentThread().getName() + "增加库存至: " + goodsCount.addAndGet(1));
                    } else {
                        add = false;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    producerSm.release();
                }
            }

        }
    };

    private Runnable consumerR = () -> {
        while (true) {
            while (!add) {
                try {
                    consumerSm.acquire();
                    if (goodsCount.get() > 0) {
                        Thread.sleep(200);
                        System.out.println(Thread.currentThread().getName() + "增加库存至: " + goodsCount.decrementAndGet());
                    } else {
                        add = true;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    consumerSm.release();
                }
            }
        }
    };

    public static void main(String[] args) {
        ProducerConsumerSM producerConsumer = new ProducerConsumerSM(0, 2, 1);
        Thread threadProducerA = new Thread(producerConsumer.producerR, "ProducerT1");
        Thread threadProducerB = new Thread(producerConsumer.producerR, "ProducerT2");
        Thread threadConsumerA = new Thread(producerConsumer.consumerR, "ConsumerT1");
        Thread threadConsumerB = new Thread(producerConsumer.consumerR, "ConsumerT2");

        threadProducerA.start();
        threadProducerB.start();
        threadConsumerA.start();
        threadConsumerB.start();
    }
}
